{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "5cf7dfbc",
   "metadata": {},
   "source": [
    "可以在[Bookshop.org](https://bookshop.org/a/98697/9781098155438) 和\n",
    "[Amazon](https://www.amazon.com/_/dp/1098155432?smid=ATVPDKIKX0DER&_encoding=UTF8&tag=oreilly20-20&_encoding=UTF8&tag=greenteapre01-20&linkCode=ur2&linkId=e2a529f94920295d27ec8a06e757dc7c&camp=1789&creative=9325)获取纸制版和电子版的*Think Python 3e*."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "bde1c3f9",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from os.path import basename, exists\n",
    "\n",
    "def download(url):\n",
    "    filename = basename(url)\n",
    "    if not exists(filename):\n",
    "        from urllib.request import urlretrieve\n",
    "\n",
    "        local, _ = urlretrieve(url, filename)\n",
    "        print(\"Downloaded \" + str(local))\n",
    "    return filename\n",
    "\n",
    "download('https://gitee.com/regentsai/Think_Python_3e_CN/blob/master/thinkpython.py');\n",
    "download('https://gitee.com/regentsai/Think_Python_3e_CN/blob/master/diagram.py');\n",
    "\n",
    "import thinkpython"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3c25ca7e",
   "metadata": {},
   "source": [
    "# 第9章：列表\n",
    "\n",
    "本章展示Python最有用的内建类型之一：列表。你将学习更多关于对象的内容，以及多个变量指向同一个对象会发生什么。\n",
    "\n",
    "在本章结尾，我们将创建一个单词列表，使用它搜索特殊的单词，比如回文词和变位词。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4d32b3e2",
   "metadata": {},
   "source": [
    "## 列表是一个序列\n",
    "\n",
    "与字符串一样，**列表list**是值的序列。在一个字符串中，值是字符；在列表中，值可以是任意类型。列表中的值称为**元素elements**。\n",
    "\n",
    "创建新列表有几种方式。最简单的方式是将元素用方括号(`[`和`]`)包围。例如，以下是包含两个整数的列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "a16a119b",
   "metadata": {},
   "outputs": [],
   "source": [
    "numbers = [42, 123]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b5d6112c",
   "metadata": {},
   "source": [
    "以下是3个字符串的列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "ac7a4a0b",
   "metadata": {},
   "outputs": [],
   "source": [
    "cheeses = ['Cheddar', 'Edam', 'Gouda']"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "dda58c67",
   "metadata": {},
   "source": [
    "列表的元素不需要是相同的类别。以下列表包含一个字符串，一个浮点数，一个整数，甚至另一个列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "18fb0e21",
   "metadata": {},
   "outputs": [],
   "source": [
    "t = ['spam', 2.0, 5, [10, 20]]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "147fa217",
   "metadata": {},
   "source": [
    "在列表内的列表是**嵌套的nested**列表。\n",
    "\n",
    "不包含元素的列表称为空列表，你可以用空的方括号`[]`创建空列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "0ff58916",
   "metadata": {},
   "outputs": [],
   "source": [
    "empty = []"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f95381bc",
   "metadata": {},
   "source": [
    "`len`函数返回列表的长度。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "f3153f36",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(cheeses)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "371403a3",
   "metadata": {},
   "source": [
    "空列表的长度为`0`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "58727d35",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "len(empty)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d3589a5d",
   "metadata": {},
   "source": [
    "接下来的图片显示了`cheeses`, `numbers`和`empty`的状态图。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "25582cad",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from diagram import make_list, Binding, Value\n",
    "\n",
    "list1 = make_list(cheeses, dy=-0.3, offsetx=0.17)\n",
    "binding1 = Binding(Value('cheeses'), list1)\n",
    "\n",
    "list2 = make_list(numbers, dy=-0.3, offsetx=0.17)\n",
    "binding2 = Binding(Value('numbers'), list2)\n",
    "\n",
    "list3 = make_list(empty, dy=-0.3, offsetx=0.1)\n",
    "binding3 = Binding(Value('empty'), list3)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "925c7d67",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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npw8eZJNmzaRl5dHcHCw9fzl/ygIRBoZi8WCv78/mZmZ9V4/ePAgTZs2tT63t7evd9cte3t7ampqrumYEydOJC4uji5dutCuXTt69ep1bY2XBqEgEGlkIiIi2LdvH+vWrSM6Oho4v8DbvHnzq6onJyeHvXv30r17dz744AOio6MxmUy4ublZp4Eu8PHxwcvLi6eeeoq33377snV6enry4IMPXv1JXYPs7Gyys7Opra0lLCzsimsFRqc1ApFGpmXLlqxZs4YZM2YQEBBAz549ef7556mrq7uqeqKionjttdcIDAxkzZo1zJs3D4B7772XiooKAgICSEhIsG4/fvx4ampqGDVqlE3P51rU1tayZ88egoKCePbZZ4mJiVEIXIG+NSQiF1m8eDFfffUVX3755e/eZ8KECbRv356pU6fewJbZlr41dJ5GBCJyXQ4dOoSPjw8FBQUkJiY2dHPkGmhEICKGpRHBeRoRiIgYnIJARMTgFAQiIganIBARMTgtFouIGJxGBCIiBqcgEBExOAWBiIjBKQhERAxOQSAiYnAKAhERg1MQiIgYnIJARMTgFAQiIganIBARMTgFgYiIwSkIREQMTkEgImJwCgIREYNTEIiIGJyCQETE4BQEIiIGpyAQETE4BYGIiMH9PwTOQVZSGxeVAAAAAElFTkSuQmCC",
      "text/plain": [
       "<Figure size 366x158 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from diagram import diagram, adjust, Bbox\n",
    "\n",
    "width, height, x, y = [3.66, 1.58, 0.45, 1.2]\n",
    "ax = diagram(width, height)\n",
    "bbox1 = binding1.draw(ax, x, y)\n",
    "bbox2 = binding2.draw(ax, x+2.25, y)\n",
    "bbox3 = binding3.draw(ax, x+2.25, y-1.0)\n",
    "\n",
    "bbox = Bbox.union([bbox1, bbox2, bbox3])\n",
    "#adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "503f25d8",
   "metadata": {},
   "source": [
    "列表的表示形式为一个盒子，上方标注“list”，内部是带有编号的元素。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e0b8ff01",
   "metadata": {},
   "source": [
    "## 列表是可变的\n",
    "\n",
    "要访问列表的一个元素，我们可以使用方括号运算符。第1个元素的索引为`0`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "9deb85a3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'Cheddar'"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "cheeses[0]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9747e951",
   "metadata": {},
   "source": [
    "与字符串不同，列表是可变的。当方括号运算符出现在赋值语句左侧，它标识要被赋值的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "98ec5d9c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[42, 17]"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "numbers[1] = 17\n",
    "numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5097a517",
   "metadata": {},
   "source": [
    "`numbers`的第2个元素从`123`变为`17`。列表索引与字符串索引的用法相同：\n",
    "\n",
    "- 整数表达式可以用作索引；\n",
    "- 如果要想读写不存在索引的元素，将获得`IndexError`；\n",
    "- 如果索引是负数，它从列表结尾开始数；\n",
    "\n",
    "`in`运算符可用于列表，检查给定元素是否存在与列表中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "000aed26",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'Edam' in cheeses"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "bcb8929c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'Wensleydale' in cheeses"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "89d01ebf",
   "metadata": {},
   "source": [
    "尽管列表可以包含另一个列表，嵌套列表依然算作单个元素。所以在下面的列表中，只有4个元素："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "5ad51a26",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = ['spam', 2.0, 5, [10, 20]]\n",
    "len(t)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4e0ea41d",
   "metadata": {},
   "source": [
    "`10`不是t的元素，因为它是嵌套列表的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "156dbc10",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "10 in t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1ee7a4d9",
   "metadata": {},
   "source": [
    "## 列表切片\n",
    "\n",
    "切片运算符在列表和字符串上的用法相同。下面的例子从有4个元素的列表中选择第2和第3个元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "70b16371",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['b', 'c']"
      ]
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters = ['a', 'b', 'c', 'd']\n",
    "letters[1:3]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bc59d952",
   "metadata": {},
   "source": [
    "如果你略去第1个索引，切片从头开始。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "e67bab33",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b']"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[:2]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1aaaae86",
   "metadata": {},
   "source": [
    "如果你略去第2个索引，切片直到结束。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "a310f506",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['c', 'd']"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[2:]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "67ad02e8",
   "metadata": {},
   "source": [
    "如果你略去了两个索引，切片是整个列表的副本。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "1385a75e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c', 'd']"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters[:]"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9232c1ef",
   "metadata": {},
   "source": [
    "另外一种复制列表的方式是使用`list`函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "a0ca0135",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c', 'd']"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(letters)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "50e4b182",
   "metadata": {},
   "source": [
    "由于`list`是内建的函数名字，你应该避免将其作为变量的名字。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b057c0c",
   "metadata": {},
   "source": [
    "## 列表运算符\n",
    "\n",
    "`+`运算符拼接多个列表。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "66804de0",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1, 2, 3, 4]"
      ]
     },
     "execution_count": 21,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t1 = [1, 2]\n",
    "t2 = [3, 4]\n",
    "t1 + t2"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "474a5c40",
   "metadata": {},
   "source": [
    "`*`运算符重复列表指定次数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "id": "96620f93",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['spam', 'spam', 'spam', 'spam']"
      ]
     },
     "execution_count": 22,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "['spam'] * 4"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "5b33bc51",
   "metadata": {},
   "source": [
    "其他数学运算符对列表无效，但内建的函数`sum`可以将列表中的元素加起来。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 23,
   "id": "0808ed08",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "3"
      ]
     },
     "execution_count": 23,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sum(t1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f216a14d",
   "metadata": {},
   "source": [
    "`min`和`max`寻找最小和最大的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 24,
   "id": "7ed7e53d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 24,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "min(t1)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "dda02e4e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "4"
      ]
     },
     "execution_count": 25,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "max(t2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "533a2009",
   "metadata": {},
   "source": [
    "## 列表的方法\n",
    "\n",
    "Python提供操作列表的方法。例如，`append`增加一个新的元素到列表末尾。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 26,
   "id": "bcf04ef9",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c', 'd', 'e']"
      ]
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters.append('e')\n",
    "letters"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ccc57f77",
   "metadata": {},
   "source": [
    "`extend`接受一个列表作为参数，将参数中的所有元素追加到列表末尾。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 27,
   "id": "be55916d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c', 'd', 'e', 'f', 'g']"
      ]
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters.extend(['f', 'g'])\n",
    "letters"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f39d9f6",
   "metadata": {},
   "source": [
    "有两个方法可以从列表移除元素。如果你知道你想要的元素索引，你可以使用`pop`方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 28,
   "id": "b22da905",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'b'"
      ]
     },
     "execution_count": 28,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t = ['a', 'b', 'c']\n",
    "t.pop(1)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6729415a",
   "metadata": {},
   "source": [
    "返回值是被移除的元素的值。我们可以确认列表已经被修改了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 29,
   "id": "01bdff91",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'c']"
      ]
     },
     "execution_count": 29,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1e97ee7d",
   "metadata": {},
   "source": [
    "如果你知道你想要移除的元素值，但不知道索引，你可以使用`remove`方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 30,
   "id": "babe366e",
   "metadata": {},
   "outputs": [],
   "source": [
    "t = ['a', 'b', 'c']\n",
    "t.remove('b')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "60e710fe",
   "metadata": {},
   "source": [
    "`remove`的返回值为`None`。但我们可以确认列表已经被修改了。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "id": "f80f5b1d",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'c']"
      ]
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2a9448a8",
   "metadata": {},
   "source": [
    "如果你查找的元素不在列表中，将产生ValueError。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "id": "861f8e7e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "ValueError",
     "evalue": "list.remove(x): x not in list",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31mValueError\u001b[0m\u001b[0;31m:\u001b[0m list.remove(x): x not in list\n"
     ]
    }
   ],
   "source": [
    "%%expect ValueError\n",
    "\n",
    "t.remove('d')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "18305f96",
   "metadata": {},
   "source": [
    "## 列表和字符串\n",
    "\n",
    "字符串是字符的序列，列表是值的序列，但字符的列表与字符串不相同。要从字符串转化为字符的列表，你可以使用`list`函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "1b50bc13",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['s', 'p', 'a', 'm']"
      ]
     },
     "execution_count": 33,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'spam'\n",
    "t = list(s)\n",
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0291ef69",
   "metadata": {},
   "source": [
    "`list`函数将字符串分解为单独的字母。如果你想要将字符串分解为单词，你可以使用字符串的`split`方法："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 34,
   "id": "c28e5127",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['pining', 'for', 'the', 'fjords']"
      ]
     },
     "execution_count": 34,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'pining for the fjords'\n",
    "t = s.split()\n",
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0e16909d",
   "metadata": {},
   "source": [
    "split的方法有可选参数**分隔符delimiter**，指定哪些字符可以作为单词的边界。以下例子使用连字符作为分隔符。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 35,
   "id": "ec6ea206",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['ex', 'parrot']"
      ]
     },
     "execution_count": 35,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "s = 'ex-parrot'\n",
    "t = s.split('-')\n",
    "t"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7c61f916",
   "metadata": {},
   "source": [
    "如果你有一个字符串的列表，你可以使用`join`将其拼接为一个字符串。`join`是字符串的方法，因此必须在分隔符上调用，并将列表作为参数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "75c74d3c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'pining for the fjords'"
      ]
     },
     "execution_count": 36,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "delimiter = ' '\n",
    "t = ['pining', 'for', 'the', 'fjords']\n",
    "s = delimiter.join(t)\n",
    "s"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "bedd842b",
   "metadata": {},
   "source": [
    "在这个例子里分隔符是空格字符，所以`join`方法将空格放到每个单词之间。如果不想要空格，你可以使用空字符串`''`作为分隔符。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "181215ce",
   "metadata": {},
   "source": [
    "## 遍历列表\n",
    "\n",
    "你可以使用`for`语句遍历列表的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "a5df1e10",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Cheddar\n",
      "Edam\n",
      "Gouda\n"
     ]
    }
   ],
   "source": [
    "for cheese in cheeses:\n",
    "    print(cheese)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c0e53a09",
   "metadata": {},
   "source": [
    "例如，在使用`split`创建字符串的列表后，我们可以用`for`语句进行遍历。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "76b2c2e3",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pining\n",
      "for\n",
      "the\n",
      "fjords\n"
     ]
    }
   ],
   "source": [
    "s = 'pining for the fjords'\n",
    "\n",
    "for word in s.split():\n",
    "    print(word)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0857b55b",
   "metadata": {},
   "source": [
    "`for`遍历空列表时，不会运行缩进的循环体语句。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "7e844887",
   "metadata": {},
   "outputs": [],
   "source": [
    "for x in []:\n",
    "    print('这个语句永远不会执行。')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6e5f55c9",
   "metadata": {},
   "source": [
    "## 列表排序\n",
    "\n",
    "Python提供内建的函数`sorted`，对列表的元素进行排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 40,
   "id": "9db54d53",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['a', 'b', 'c']"
      ]
     },
     "execution_count": 40,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scramble = ['c', 'a', 'b']\n",
    "sorted(scramble)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44e028cf",
   "metadata": {},
   "source": [
    "初始的列表没有被修改。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 41,
   "id": "33d11287",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['c', 'a', 'b']"
      ]
     },
     "execution_count": 41,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scramble"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "530146af",
   "metadata": {},
   "source": [
    "`sorted`对任何种类的序列有效。所以我们可以像这样对字符串中的字母进行排序。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 42,
   "id": "38c7cb0c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['e', 'e', 'l', 'r', 's', 't', 't']"
      ]
     },
     "execution_count": 42,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sorted('letters')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f90bd9ea",
   "metadata": {},
   "source": [
    "结果是一个列表，要将其转化为字符串，我们可以使用`join`方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 43,
   "id": "2adb2fc3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'eelrstt'"
      ]
     },
     "execution_count": 43,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "''.join(sorted('letters'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a57084e2",
   "metadata": {},
   "source": [
    "再次说明，使用空字符串作为分隔符，列表的元素会直接拼接在一起。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce98b3d5",
   "metadata": {},
   "source": [
    "## 对象和值\n",
    "\n",
    "如果我们执行这些赋值语句："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 44,
   "id": "aa547282",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'banana'\n",
    "b = 'banana'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "33d020aa",
   "metadata": {},
   "source": [
    "我们知道`a`和`b`都指向一个字符串，但我们不知道它们是否指向*同一个*字符串。和下面图像中显示的一样，有两种可能的状态。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 45,
   "id": "95a2aded",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from diagram import Frame, Stack\n",
    "\n",
    "s = 'banana'\n",
    "bindings = [Binding(Value(name), Value(repr(s))) for name in 'ab']\n",
    "frame1 = Frame(bindings, dy=-0.25)\n",
    "\n",
    "binding1 = Binding(Value('a'), Value(repr(s)), dy=-0.11)\n",
    "binding2 = Binding(Value('b'), draw_value=False, dy=0.11)\n",
    "frame2 = Frame([binding1, binding2], dy=-0.25)\n",
    "\n",
    "stack = Stack([frame1, frame2], dx=1.7, dy=0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 46,
   "id": "3d75a28c",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 285x76 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "width, height, x, y = [2.85, 0.76, 0.17, 0.51]\n",
    "ax = diagram(width, height)\n",
    "bbox = stack.draw(ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2f0b0431",
   "metadata": {},
   "source": [
    "在左边的图中，`a`和`b`指向两个有相等值的不同对象。在右边的图中，它们指向同一个对象。要检查两个变量是否指向同一个对象，你可以使用`is`运算符。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 47,
   "id": "a37e37bf",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 47,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = 'banana'\n",
    "b = 'banana'\n",
    "a is b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d1eb0e36",
   "metadata": {},
   "source": [
    "在这个例子里，Python只创建了一个字符串对象，`a`和`b`指向同一个对象。\n",
    "\n",
    "但当你创建两个列表时，你会得到两个对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 48,
   "id": "d6af7316",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 48,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "b = [1, 2, 3]\n",
    "a is b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a8d4c3d4",
   "metadata": {},
   "source": [
    "所以状态图看起来像这样："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 49,
   "id": "dea08b82",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "t = [1, 2, 3]\n",
    "binding1 = Binding(Value('a'), Value(repr(t)))\n",
    "binding2 = Binding(Value('b'), Value(repr(t)))\n",
    "frame = Frame([binding1, binding2], dy=-0.25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 50,
   "id": "7e66ee69",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 116x76 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "width, height, x, y = [1.16, 0.76, 0.21, 0.51]\n",
    "ax = diagram(width, height)\n",
    "bbox = frame.draw(ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "cc115a9f",
   "metadata": {},
   "source": [
    "在这个例子里我们可以说两个列表是**相等的equivalent**，因为它们有相同的元素，但不是**同一的identical**，因为他们不是同一个对象。\n",
    "\n",
    "如果两个对象是同一的，它们必然相等；如果两个对象相等，它们未必同一。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a58db021",
   "metadata": {},
   "source": [
    "## 别名\n",
    "\n",
    "如果`a`指向一个对象，你赋值`b = a`，那么两个变量指向的是同一个对象。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 51,
   "id": "d6a7eb5b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 51,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a = [1, 2, 3]\n",
    "b = a\n",
    "b is a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f6ab3262",
   "metadata": {},
   "source": [
    "状态图如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 52,
   "id": "dd406791",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "t = [1, 2, 3]\n",
    "binding1 = Binding(Value('a'), Value(repr(t)), dy=-0.11)\n",
    "binding2 = Binding(Value('b'), draw_value=False, dy=0.11)\n",
    "frame = Frame([binding1, binding2], dy=-0.25)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 53,
   "id": "552e1e1e",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 111x81 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "width, height, x, y = [1.11, 0.81, 0.17, 0.56]\n",
    "ax = diagram(width, height)\n",
    "bbox = frame.draw(ax, x, y)\n",
    "# adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c676fde9",
   "metadata": {},
   "source": [
    "变量和对象之间的联系称为**引用reference**。在这个例子中，同一个对象有两个引用。\n",
    "\n",
    "有多个引用的对象有多个名字，所以我们说该对象**有别名aliased**。如果有别名的对象可变，对一个名字的改变会影响另一个名字。在这个例子里，如果我们修改变量名`b`引用的对象，也会修改变量名`a`引用的对象。\n",
    "\n",
    "译注：Python中的变量名总是联系到某个对象的`引用reference`。将`refer to`翻译为`指向`符合日常表示习惯，但在技术上可能引起误解。本节作为区分将`refer to`明确翻译为`引用`，而在其他章节翻译为`指向`。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 54,
   "id": "6e3c1b24",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[5, 2, 3]"
      ]
     },
     "execution_count": 54,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b[0] = 5\n",
    "a"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e3ef0537",
   "metadata": {},
   "source": [
    "我们说`a`“看到”了这个改变。尽管这个行为很有用，它也可能导致错误。总体而言，当处理可变对象时避免用别名会更安全。\n",
    "\n",
    "对于字符串等不可变的对象，别名基本不是问题。在这个例子中："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "dad8a246",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = 'banana'\n",
    "b = 'banana'"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "952bbf60",
   "metadata": {},
   "source": [
    "基本上不管`a`和`b`是否指向同一个字符串，都没有影响。\n",
    "\n",
    "译注:字符串是不可变的,对`a`的修改实际上是重新赋值,`a`与原字符串之间的联系(引用)将被移除,自然不会影响`b`的值."
   ]
  },
  {
   "cell_type": "markdown",
   "id": "35045bef",
   "metadata": {},
   "source": [
    "## 列表作为参数\n",
    "\n",
    "当你传递参数给函数时，函数将获得列表的引用。如果函数修改了列表，调用者会看见修改。例如，`pop_first`使用列表的方法`pop`移除列表的第1个元素。\n",
    "\n",
    "译注：注意该函数的形参名为lst,以避免使用内建的名称list。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 55,
   "id": "613b1845",
   "metadata": {},
   "outputs": [],
   "source": [
    "def pop_first(lst):\n",
    "    return lst.pop(0)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4953b0f9",
   "metadata": {},
   "source": [
    "我们可以像这样使用函数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 56,
   "id": "3aff3598",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'a'"
      ]
     },
     "execution_count": 56,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters = ['a', 'b', 'c']\n",
    "pop_first(letters)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ef5d3c1e",
   "metadata": {},
   "source": [
    "返回的值是第一个元素，从列表中移除了。我们可以通过显示修改的列表来进行查看。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 57,
   "id": "c10e4dcc",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['b', 'c']"
      ]
     },
     "execution_count": 57,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "letters"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e5288e08",
   "metadata": {},
   "source": [
    "在这个例子中，形参`lst`与实参变量`letters`是同一个对象的别名，所以状态图如下："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 58,
   "id": "a13e72c7",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "lst = make_list('abc', dy=-0.3, offsetx=0.1)\n",
    "binding1 = Binding(Value('letters'), draw_value=False)\n",
    "frame1 = Frame([binding1], name='__main__', loc='left')\n",
    "\n",
    "binding2 = Binding(Value('lst'), draw_value=False, dx=0.61, dy=0.35)\n",
    "frame2 = Frame([binding2], name='pop_first', loc='left', offsetx=0.08)\n",
    "\n",
    "stack = Stack([frame1, frame2], dx=-0.3, dy=-0.5)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 59,
   "id": "1a06dae9",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[2.04, 1.22, 1.06, 0.85]"
      ]
     },
     "execution_count": 59,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "image/png": "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",
      "text/plain": [
       "<Figure size 204x124 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "width, height, x, y = [2.04, 1.24, 1.06, 0.85]\n",
    "ax = diagram(width, height)\n",
    "bbox1 = stack.draw(ax, x, y)\n",
    "bbox2 = lst.draw(ax, x+0.5, y)\n",
    "bbox = Bbox.union([bbox1, bbox2])\n",
    "adjust(x, y, bbox)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c1a093d2",
   "metadata": {},
   "source": [
    "将对象的引用作为函数的实参创建了一种形式的别名。如果函数修改了对象，这些改变在函数结束之后会保留。\n",
    "\n",
    "译注：与列表相反，将不可变对象作为实参传递给函数，尽管在函数内部会创建该对象的别名，但对别名的修改过程与`para=arg;para=1`类似，不会影响实参`arg`的值。除非使用`global`关键字。使用`global`通常不是好的方法，且原书不对其进行介绍，后续章节会提供更合适的方法。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "88c07ec9",
   "metadata": {
    "tags": []
   },
   "source": [
    "## 创建单词列表\n",
    "\n",
    "在之前的章节，我们读取文件`words.txt`，并搜索有特别属性的单词，比如使用字母`e`的单词。但我们多次读取了整个文件，这效率不高。\n",
    "\n",
    "读取文件一次，将单词放到列表中更好。以下循环显示如何执行这个操作。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 60,
   "id": "6550f0b8",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "download('https://gitee.com/regentsai/Think_Python_3e_CN/blob/master/words.txt');"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 61,
   "id": "e5a94833",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "113783"
      ]
     },
     "execution_count": 61,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word_list = []\n",
    "\n",
    "for line in open('words.txt'):\n",
    "    word = line.strip()\n",
    "    word_list.append(word)\n",
    "    \n",
    "len(word_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "44450ffa",
   "metadata": {},
   "source": [
    "在循环之前，`word_list`被初始化为空列表。循环过程中的每一轮，`append`方法将一个单词追加到列表的末尾。当循环结束时，列表中包括超过11.3万个单词。\n",
    "\n",
    "另一种方式是使用文件对象的`read`方法，将整个文件文本读取为一个字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 62,
   "id": "32e28204",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1016511"
      ]
     },
     "execution_count": 62,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "string = open('words.txt').read()\n",
    "len(string)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "65718c7f",
   "metadata": {},
   "source": [
    "该字符串中包含超过一百万个字符。我们可以使用`split`方法将其分割到单词列表中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 63,
   "id": "4e35f7ce",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "113783"
      ]
     },
     "execution_count": 63,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word_list = string.split()\n",
    "len(word_list)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "1b5b25a3",
   "metadata": {},
   "source": [
    "现在，要检查某个字符串是否在列表中，我们可以使用`in`运算符。例如，`'demotic'`在该列表中。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 64,
   "id": "a778a62a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "True"
      ]
     },
     "execution_count": 64,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'demotic' in word_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "9df6674d",
   "metadata": {},
   "source": [
    "但是`'contrafibularities'`不在其中，我得说，我对这感到难受（anaspeptic）。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 65,
   "id": "63341c0e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "False"
      ]
     },
     "execution_count": 65,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "'contrafibularities' in word_list"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ce9ffd79",
   "metadata": {},
   "source": [
    "## 调试\n",
    "\n",
    "注意大多数列表的方法修改列表后返回`None`。这与字符串方法相反，字符串方法返回新的字符串，让旧的字符串保持不变。\n",
    "\n",
    "如果你习惯像这样编写处理字符串的代码："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 66,
   "id": "88872f14",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'plumage'"
      ]
     },
     "execution_count": 66,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "word = 'plumage!'\n",
    "word = word.strip('!')\n",
    "word"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d2117582",
   "metadata": {},
   "source": [
    "想这样编写列表的代码很有诱惑："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 67,
   "id": "e28e7135",
   "metadata": {},
   "outputs": [],
   "source": [
    "t = [1, 2, 3]\n",
    "t = t.remove(3)           # 错误!"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "991c439d",
   "metadata": {},
   "source": [
    "`remove`修改列表并返回`None`，所以对`t`的后续操作很有可能失败。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 68,
   "id": "97cf0c61",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "ename": "AttributeError",
     "evalue": "'NoneType' object has no attribute 'remove'",
     "output_type": "error",
     "traceback": [
      "\u001b[0;31mAttributeError\u001b[0m\u001b[0;31m:\u001b[0m 'NoneType' object has no attribute 'remove'\n"
     ]
    }
   ],
   "source": [
    "%%expect AttributeError\n",
    "\n",
    "t.remove(2)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "c500e2d8",
   "metadata": {},
   "source": [
    "这个错误信息需要更多解释。对象的**属性attribute**是绑定到这个对象的变量或者函数。在这个例子里，`t`的值为`None`，它是`NoneType`类型，没有属性名为`remove`，所以结果是`AttributeError`。\n",
    "\n",
    "如果你看到类似的错误信息，你应该回顾程序，看看你是否错误调用了一个列表函数。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f90db780",
   "metadata": {},
   "source": [
    "## 术语表\n",
    "\n",
    "- **列表list**：一种包含值的序列的对象；\n",
    "- **元素element**：列表或者其他序列中的某个值；\n",
    "- **嵌套列表nested list**：作为其他列表元素的列表；\n",
    "- **分隔符delimiter**：一个表示字符串哪里应该分割的字符或者字符串；\n",
    "- **相等equivalent**：拥有相同的值；\n",
    "- **同一identical**：是同一个对象（蕴含了相等）；\n",
    "- **引用reference**：变量名和值之间的联系；\n",
    "- **有别名aliased**：如果对象有多个变量引用，该对象有别名；\n",
    "- **属性attribute**：与对象联系的某个值的名字。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e67864e5",
   "metadata": {},
   "source": [
    "## 练习"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "id": "a4e34564",
   "metadata": {
    "tags": []
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Exception reporting mode: Verbose\n"
     ]
    }
   ],
   "source": [
    "# 这个单元格让Jupyter在出现运行时故障时提供更多调试信息。\n",
    "# 在进行练习前先运行本单元格。\n",
    "\n",
    "%xmode Verbose"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ae9c42da",
   "metadata": {},
   "source": [
    "### 询问虚拟助手\n",
    "\n",
    "在本章，我使用了单词\"contrafibularities\"和\"anaspeptic\"，但它们不是真实的英语单词，它们在英国电视剧*Black Adder*第3季第2集\"Ink and Incapability\"中出现。\n",
    "\n",
    "然而，当我询问ChatGPT 3.5 (August 3, 2023 版本时)，它一开始声称它们来自Monty Python，后来又声称它们来自戏剧*Rosencrantz and Guildenstern Are Dead*。\n",
    "\n",
    "如果你现在询问，你可能获得不同的结果。但这个例子意在提醒你，虚拟助手不总是准确，所以你需要检查结果是否正确。当你的经验变得丰富，你将对虚拟助手能可靠地问答什么问题建立一种直觉。对于这个例子，传统的网络搜索引擎可以快速辨别这些单词的出处。\n",
    "\n",
    "如果你被本章的任何练习卡住，考虑寻求虚拟助手的协助。如果虚拟助手提供了你还没学习的功能，你可以赋予虚拟助手一个“角色”。\n",
    "\n",
    "例如，在你问问题之前，尝试输入“你的角色是Python编程初学者的导师。”然后，你得到的回复应该只使用基础的功能。如果你依然看到没学过的功能，你可以接着问：“你能只使用基础Python功能编写这个代码吗？”"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "31d5b304",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "一个单词重新排列字母，成为第2个单词，则这两个单词互为变位词。例如，`tops`是`stop`的变位词。\n",
    "\n",
    "对两个单词排序后进行比较是检查两个单词是否变位的一种方法。如果排序后的字母相同，两个单词互为变位词。\n",
    "\n",
    "编写函数`is_anagram`，接受两个字符串，如果是变位词就返回`True`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a882bfeb",
   "metadata": {
    "tags": []
   },
   "source": [
    "以下是函数的框架，包含文档测试。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "9c5916ed",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def is_anagram(word1, word2):\n",
    "    \"\"\"检查两个单词是否为变位词。\n",
    "    \n",
    "    >>> is_anagram('tops', 'stop')\n",
    "    True\n",
    "    >>> is_anagram('skate', 'takes')\n",
    "    True\n",
    "    >>> is_anagram('tops', 'takes')\n",
    "    False\n",
    "    >>> is_anagram('skate', 'stop')\n",
    "    False\n",
    "    \"\"\"\n",
    "    return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "5885cbd3",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a86e7403",
   "metadata": {
    "tags": []
   },
   "source": [
    "你可以使用`doctest`测试你的函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "ce7a96ec",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "from doctest import run_docstring_examples\n",
    "\n",
    "def run_doctests(func):\n",
    "    run_docstring_examples(func, globals(), name=func.__name__)\n",
    "\n",
    "run_doctests(is_anagram)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8501f3ba",
   "metadata": {},
   "source": [
    "使用你的函数和单词列表，找出`takes`的所有变位词。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "75e17c7b",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7f279f2f",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "Python提供了内建的函数`reversed`，接受一个序列，比如列表或字符串，返回一个`reversed`对象，包含相反顺序的元素。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "id": "aafa5db5",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<reversed at 0x7a18f3d0a6b0>"
      ]
     },
     "execution_count": 71,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "reversed('parrot')"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0f95c76f",
   "metadata": {},
   "source": [
    "如果你想要把翻转的元素保存到列表中，你可以使用`list`函数。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "id": "06cbb42a",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['t', 'o', 'r', 'r', 'a', 'p']"
      ]
     },
     "execution_count": 72,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "list(reversed('parrot'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8fc79a2f",
   "metadata": {},
   "source": [
    "或者如果你想要将其保存到字符串中，你可以使用`join`方法。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "id": "18a73205",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "'torrap'"
      ]
     },
     "execution_count": 73,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "''.join(reversed('parrot'))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ec4ce196",
   "metadata": {},
   "source": [
    "因此我们可以编写一个函数，翻转单词。\n",
    "\n",
    "译注：与之前章节相同，你也可以使用`word[::-1]`翻转字符串。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "id": "408932cb",
   "metadata": {},
   "outputs": [],
   "source": [
    "def reverse_word(word):\n",
    "    return ''.join(reversed(word))"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "21550b5f",
   "metadata": {},
   "source": [
    "回文词从前向后和从后向前的拼写顺序相同，例如\"noon\"和\"rotator\"。编写函数`is_palindrome`，接受一个字符串，如果是回文词则返回`True`。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "3748b4e0",
   "metadata": {
    "tags": []
   },
   "source": [
    "以下是函数的框架，包含文档测试。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "id": "9179d51c",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def is_palindrome(word):\n",
    "    \"\"\"检查单词是否为回文词。\n",
    "    \n",
    "    >>> is_palindrome('bob')\n",
    "    True\n",
    "    >>> is_palindrome('alice')\n",
    "    False\n",
    "    >>> is_palindrome('a')\n",
    "    True\n",
    "    >>> is_palindrome('')\n",
    "    True\n",
    "    \"\"\"\n",
    "    return False"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "id": "16d493ad",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "id": "33c9b4ec",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "run_doctests(is_palindrome)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ad857abf",
   "metadata": {},
   "source": [
    "你可以使用以下循环找出单词列表中长度至少为7的回文词。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "id": "fea01394",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "for word in word_list:\n",
    "    if len(word) >= 7 and is_palindrome(word):\n",
    "        print(word)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "11386f70",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "编写函数`reverse_sentence`，接受一个字符串作为参数，字符串由若干空格分隔的单词组成。该函数返回新字符串，包含相反顺序的单词。例如，\"Reverse this sentence\"对应的返回值应该为\"Sentence this reverse\"。\n",
    "\n",
    "提示：你可以使用`capitalize`方法将字符串的第一个字母变为大写，其他字母变为小写。"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "13882893",
   "metadata": {
    "tags": []
   },
   "source": [
    "以下是函数的框架，包含文档测试。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 83,
   "id": "d9b5b362",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "def reverse_sentence(input_string):\n",
    "    '''翻转字符串中单词的顺序，将第1个字母大写。\n",
    "    \n",
    "    >>> reverse_sentence('Reverse this sentence')\n",
    "    'Sentence this reverse'\n",
    "\n",
    "    >>> reverse_sentence('Python')\n",
    "    'Python'\n",
    "\n",
    "    >>> reverse_sentence('')\n",
    "    ''\n",
    "\n",
    "    >>> reverse_sentence('One for all and all for one')\n",
    "    'One for all and all for one'\n",
    "    '''\n",
    "    return None"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 84,
   "id": "a2cb1451",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 85,
   "id": "769d1c7a",
   "metadata": {
    "tags": []
   },
   "outputs": [],
   "source": [
    "run_doctests(reverse_sentence)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "fb5f24b1",
   "metadata": {},
   "source": [
    "### 练习\n",
    "\n",
    "编写函数`total_length`，接受包含字符串的列表，返回这些字符串的总长度。单词列表`word_list`中字符串的总长度应该为$902{,}728$。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "1fba5377",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "21f4cf1c",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 在这解答"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "c3efb216",
   "metadata": {},
   "outputs": [],
   "source": []
  },
  {
   "cell_type": "markdown",
   "id": "a7f4edf8",
   "metadata": {
    "tags": []
   },
   "source": [
    "[Think Python: 3rd Edition](https://allendowney.github.io/ThinkPython/index.html)\n",
    "\n",
    "Copyright 2024 [Allen B. Downey](https://allendowney.com)\n",
    "\n",
    "Code license: [MIT License](https://mit-license.org/)\n",
    "\n",
    "Text license: [Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International](https://creativecommons.org/licenses/by-nc-sa/4.0/)"
   ]
  }
 ],
 "metadata": {
  "celltoolbar": "Tags",
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
